package com.only4play.web.resources;

import com.only4play.auth.AccessTokenContent;
import com.only4play.auth.AuthenticatedUser;
import com.only4play.auth.RefreshTokenContent;
import com.only4play.common.model.GeneralResponse;
import com.only4play.constant.Oauth2Constant;
import com.only4play.domain.model.RpcAccessToken;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.Objects;

/**
 * @author liyuncong
 * @version 1.0
 * @file LoginController
 * @brief 登录控制器
 * @details 登录控制器
 * @date 2023-11-18
 * <p>
 * Edit History
 * ----------------------------------------------------------------------------
 * DATE                     NAME               DESCRIPTION
 * 2023-11-18               liyuncong          Created
 */
@RestController
@RequestMapping
public class AuthenticationResource extends AbstractBaseResource {

    /**
     * 通过授权码(ticket/code)获取accessToken及用户信息
     */
    @PostMapping(value = Oauth2Constant.ACCESS_TOKEN_URL)
    public GeneralResponse<RpcAccessToken> getAccessToken(
        @RequestParam(value = Oauth2Constant.GRANT_TYPE, required = true) String grantType,
        @RequestParam(value = Oauth2Constant.APP_ID, required = true) String appId,
        @RequestParam(value = Oauth2Constant.APP_SECRET, required = true) String appSecret,
        @RequestParam(value = Oauth2Constant.AUTH_CODE, required = false) String code,
        @RequestParam(value = Oauth2Constant.USERNAME, required = false) String username,
        @RequestParam(value = Oauth2Constant.PASSWORD, required = false) String password
    ) {
        // 校验基本参数
        validateParams(grantType, code, username, password);

        // 校验应用

        // 校验授权
        AccessTokenContent accessTokenContent = validateAuth(grantType, code, username, password, appId);
        // 生成rpcAccessToken
        RpcAccessToken rpcAccessToken = generateRpcAccessToken(accessTokenContent, null);
        return GeneralResponse.of(rpcAccessToken);
    }

    /**
     * 利用refreshToken刷新accessToken，并延长TGT超时时间
     * accessToken刷新结果有两种：
     * 1. 若accessToken已超时，那么进行refreshToken会生成一个新的accessToken，新的超时时间；
     * 2. 若accessToken未超时，那么进行refreshToken不会改变accessToken，但超时时间会刷新，相当于续期accessToken。
     */
    @PostMapping(value = Oauth2Constant.REFRESH_TOKEN_URL)
    public GeneralResponse<RpcAccessToken> refreshAccessToken(
        @RequestParam(value = Oauth2Constant.APP_ID, required = true) String appId,
        @RequestParam(value = Oauth2Constant.REFRESH_TOKEN, required = true) String refreshToken
    ) {
        // 校验应用

        // refreshToken
        RefreshTokenContent refreshTokenContent = refreshTokenManager.validate(refreshToken);
        if (Objects.isNull(refreshTokenContent)) {
            return GeneralResponse.failure("refreshToken错误或已过期");
        }

        AccessTokenContent accessTokenContent = refreshTokenContent.getAccessTokenContent();
        if (!StringUtils.equals(appId, accessTokenContent.getAppId())) {
            return GeneralResponse.failure("非法应用");
        }

        AuthenticatedUser<Void> authenticatedUser = ticketGrantingTicketManager.getAndRefresh(accessTokenContent.getCodeContent().getTgt());
        if (Objects.isNull(authenticatedUser)) {
            return GeneralResponse.failure("服务端session已过期");
        }

        // 生成新的 AccessToken
        RpcAccessToken rpcAccessToken = generateRpcAccessToken(accessTokenContent, refreshToken);
        return GeneralResponse.of(rpcAccessToken);
    }
}
